package com.someok.utils;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


/**
 * Miscellaneous and useful bean utilities.
 *
 * <p><a href="BeanUtil.java.html"><i>View Source</i></a></p>
 *
 * @version $Revision: 9 $ $Date: 2006-03-08 18:21:59 +0800 (星期三, 08 三月 2006) $
 */
public class BeanUtil {

	// ---------------------------------------------------------------- misc

	private final static String GET_PREFIX = "get";
//	private final static String SET_PREFIX = "set";
	private final static String IS_PREFIX = "is";

//	private static String name2setter(String name) {
//		return name2xxx(name, SET_PREFIX);
//	}

	private static String name2getter(String name) {
		return name2xxx(name, GET_PREFIX);
	}

	private static String name2ister(String name) {
		return name2xxx(name, IS_PREFIX);
	}

	/**
	 * Formats the name of a property methods: it adds a prefix and capitalizes
	 * the first letter of property name.
	 *
	 * @param name   name of the property
	 * @param prefix get or set
	 *
	 * @return name of the property method (i.e. getXXX() or setXXX())
	 */
	private static String name2xxx(String name, String prefix) {
		if (name.startsWith(prefix) == true) {
			return name;
		}
		name = prefix + name.substring(0, 1).toUpperCase() + name.substring(1);
		return name;
	}




	// ---------------------------------------------------------------- get

	/**
	 * Gets the value from the bean parameter. If parameter doesn't exist in the
	 * bean, <code>null</code> is returned. Property name should be specified
	 * without 'get' prefix. Nested beans are allowed, separated by a dot ('.').
	 * If getXxx() method is not found, isXxx() method will be called.
	 * <p>
	 *
	 * Method doesn't throw any exception.
	 *
	 * @param bean   java bean
	 * @param name   property name
	 *
	 * @return null if parameter doesn't exist, otherwise parameters value.
	 */
	public static Object getProperty(Object bean, String name) {
		Object result = null;
		if (name == null) {
			return null;
		}
		try {
			int dotNdx;
			while ( (dotNdx = name.indexOf('.')) != -1) {
				String methodName = name.substring(0, dotNdx);
				name = name.substring(dotNdx + 1);
				Method m = bean.getClass().getMethod(name2getter(methodName), null);
				bean = m.invoke(bean, null);
			}

			Method m = null;
			Class beanClass = bean.getClass();
			try {
				m = beanClass.getMethod(name2getter(name), null);
			} catch (NoSuchMethodException nsmex) {
				m = beanClass.getMethod(name2ister(name), null);
			}
			result = m.invoke(bean, null);
		} catch (Exception ex) {
		}
		return result;
	}

	/**
	 * Returns all bean properties (getXxx()) as a <code>Map</code> for easier
	 * and faster manipulation. Property names (without 'get') are keys and
	 * property values are map values.
	 *
	 * @param bean   java bean which properties to read
	 *
	 * @return <code>Map</code> that contains all bean properties values
	 * @see #getProperty
	 * @see #setAllProperties
	 */
	public static Map getAllProperties(Object bean) {
		HashMap data = new HashMap();
		try {
			Method[] ms = bean.getClass().getMethods();
			for (int i = 0; i < ms.length; i++) {
				String name = ms[i].getName();
				if (name.startsWith(GET_PREFIX)) {
					String pname = name.substring(3);
					// 将 key 置为大写形式
					data.put(pname.toUpperCase(), ms[i].invoke(bean, null));
				}
			}
		} catch (Exception ex){
		}
		return data;
	}


	// ---------------------------------------------------------------- toString

	/**
	 * Creates formated string that contains names of all readable properties
	 * (getXXX() methods) and their values. For debugging purposes only.
	 *
	 * @param o      java bean
	 *
	 * @return formated String that contains info about all beans properties.
	 */
	public static String toString(Object o) {
		StringBuffer result = new StringBuffer("Bean: ");
		if (o == null) {
			result.append("null");
			return result.toString();
		}
		result.append(o.getClass().getName()).append("\n");

		Method[] ms = o.getClass().getMethods();
		for (int i = 0; i < ms.length; i++) {
			Method m = ms[i];
			Class[] params = m.getParameterTypes();
			if (params.length != 0) {
				continue;								// skip methods that have params
			}
			String mname = m.getName();
			if (mname.equals("getClass")) {				// skip getClass() method
				continue;
			}
			if (mname.startsWith(GET_PREFIX)) {			// getXXX() method found
				String paramName = m.getName().substring(3);
				Object mresult = null;
				try {
					mresult = m.invoke(o, null);
				} catch (Exception ex) {
				}
				result.append("  ").append(paramName);
				if (mresult != null) {
					result.append(":[").append(mresult.toString()).append("]");
				} else {
					result.append(":null");
				}
				result.append("\n");

			}
		}
		return result.toString();
	}


}
